package gcontent.entities.content.html;

import org.apache.log4j.Logger;

import org.htmlparser.Node;
import org.htmlparser.filters.TagNameFilter;
import org.htmlparser.nodes.TagNode;
import org.htmlparser.tags.BaseHrefTag;
import org.htmlparser.tags.ImageTag;
import org.htmlparser.tags.LinkTag;
import org.htmlparser.tags.ScriptTag;
import org.htmlparser.tags.TitleTag;

import com.tecnick.htmlutils.htmlentities.HTMLEntities;

import gcontent.entities.Site;
import gcontent.entities.site.SiteURL;
import gcontent.utils.URLUtils;

import java.net.MalformedURLException;
import java.net.URL;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;

public class TagFilter extends TagNameFilter {
		
	private static final long serialVersionUID = 1L;
	
	private HashMap<String, HashMap<String, RefHTML>> map_rsrc = new HashMap<String, HashMap<String, RefHTML>>();
	private ArrayList<RefHTML> full_ref_list = new ArrayList<RefHTML>();
	private static Logger log = Logger.getLogger(TagFilter.class);
	private ContentHTML content;
	
	private String path_host = "";
	private String path_dir = "";
	private String base_url = null;
	
	public ArrayList<RefHTML> getTypeRef(String name)
	{
		HashMap<String, RefHTML> type_ref;
		ArrayList<RefHTML> site_list;
		
		type_ref = this.map_rsrc.get(name);		
		if(type_ref == null)
			return new ArrayList<RefHTML>(0);
		
		/* fill vector */
		site_list = new ArrayList<RefHTML>(type_ref.size());		
		for(Iterator<String> it = type_ref.keySet().iterator(); it.hasNext(); ) {
			String key;
			
			key = it.next();
			site_list.add(type_ref.get(key));
		}
		
		return site_list;
	}
	
	public TagFilter(ContentHTML content)
	{		
		String url;
		URL url_parent;
		
		url_parent = null;
		
		if(content.getParentSite() instanceof SiteURL) {
			url_parent = ((SiteURL)content.getParentSite()).getURL();
		} else {			
			try { url_parent = new URL("http://unknown:6969"); } catch(Exception ex){}
		}
		
		this.path_dir = URLUtils.getURLDir(url_parent);
		this.path_host = URLUtils.getURLHost(url_parent);
		
		content.setReferences(this.full_ref_list);
		
		this.content = content;
	}
	
	private void put(String name, RefHTML ref)
	{
		HashMap<String, RefHTML> values;
		
		values = this.map_rsrc.get(name);
		if(values == null) {
			values = new HashMap<String, RefHTML>();
			this.map_rsrc.put(name, values);
		} 
		
		if(values.get(ref.getURL().getPath()) != null)
			return;
				
		values.put(ref.getURL().getPath(), ref);
		
		this.full_ref_list.add(ref);		
	}
	
	public boolean accept(Node node)
	{
		Class<?> class_kind;
		boolean ret;
		
		class_kind = node.getClass();
		ret = false;
		
		if(TitleTag.class.isAssignableFrom(class_kind)) {
			TitleTag tag = (TitleTag)node;			
			this.content.setTitle(tag.getTitle());
			
		} else if(TagNode.class.isAssignableFrom(class_kind)) {
			TagNode tag = (TagNode)node;
			RefHTML ref;
			URL url_rsrc;
	
			if(tag.getAttribute("src") != null) {
				url_rsrc = buildURL(tag.getAttribute("src"));
			} else if(tag.getAttribute("href") != null) {
				if(BaseHrefTag.class.isAssignableFrom(class_kind)) {
					 try {
						 url_rsrc = new URL(tag.getAttribute("href")); 
					 } catch(Exception ex) {
						 url_rsrc = null;
					 }
				} else {
					url_rsrc = buildURL(tag.getAttribute("href"));
				} 
			} else
				url_rsrc = null;

			if(url_rsrc != null) {
				if(ImageTag.class.isAssignableFrom(class_kind)) {
					ref = new RefHTML(this.content, tag.getTagName(), url_rsrc);
					put(ImageTag.class.getName(), ref);
				} else if(LinkTag.class.isAssignableFrom(class_kind)) {
					ref = new RefHTML(this.content, tag.getTagName(), url_rsrc);
					put(LinkTag.class.getName(), ref);
				} else if(BaseHrefTag.class.isAssignableFrom(class_kind)) {
					this.base_url = url_rsrc.toString();
				} else {
					ref = new RefHTML(this.content, tag.getTagName(), url_rsrc);
					put(TagNode.class.getName(), ref);
				}
			
				ret = true;
			}
			
		}
				
		return ret;
	}
		
	/* normalize special characters from URL */
	public static String normalizeURL(String url)
	{
		int ini, end;
		
		if(url == null || url.length() == 0)
			return null;
		
		ini = 0;
		end = url.length() - 1;
		
		/* remove left and right spaces */
		while(url.charAt(ini) == ' ' || url.charAt(ini) == '\r' || url.charAt(ini) == '\n') 
			ini++;
						
		while(url.charAt(end) == ' ' || url.charAt(end) == '\r' || url.charAt(end) == '\n')
			end--;
						
		if(ini != 0 || end != (url.length() - 1)) {
			url = url.substring(ini, end + 1);
		}
			
		//url = "http://www.uab.es/Document_AAA/568/341/MATRICULA UAB 3 idiomes (ok),0.pdf";
		url = HTMLEntities.unhtmlentities(url);
		url = url.replace(" ", "%20");
		
		return url;
	}
	
	/* build a new url from reference */
	public URL buildURL(String ref)
	{
		URL ret_url;
		char ini_char;
						
		ref = normalizeURL(ref);			
		if(ref == null)
			return null;
		
		ret_url = null;
		ini_char = ref.charAt(0);
		
		try { 	
			if(ini_char == '\\' || ini_char == '"' || ini_char == '\'' || ini_char == '#')
				return null;
			
			if(ref.startsWith("//")) {
				ret_url = new URL("http:" + ref);
				
			} else if(ref.startsWith("/")) {
				ret_url = new URL((this.base_url != null? this.base_url : this.path_host) + ref);
				
			} else if(ref.contains("://")) {
				ret_url = new URL(ref);
				
			} else if (!ref.startsWith("javascript:")){
				if(this.base_url != null)
					ret_url = new URL(this.base_url + ref);
				else
					ret_url = new URL(this.path_host + this.path_dir + "/" + ref);

				
			} else {
				if(log.isDebugEnabled())
					log.debug("host => " + this.path_host + " dirbase => " + this.path_dir + 
							" url => " + ref + " not is good");
			}

		} catch(MalformedURLException ex) {
			log.warn("host => " + this.path_host + " dirbase => " + this.path_dir + 
					" url => " + ref + " is malformed - " + ex.getMessage());
		}
		
		return ret_url;
	}
	
	public void printReferences()
	{
		for(int i = 0; i < full_ref_list.size(); i++) {
			System.out.println("url ref => " + full_ref_list.get(i).getURL().toString());
		}
	}
	
}
